package udp

import (
	"fmt"
	"net"
	"smart-flow/monitor/config"
	"smart-flow/monitor/logger"
	"smart-flow/monitor/service"
	"strconv"
	"strings"

	"go.uber.org/zap"
)

type ServerManager struct {
	servers []*StatUdpServer
}

func (m *ServerManager) Start() bool {
	for _, ip := range config.PusherEndpointsInfo.StatIps {
		m.startOne(ip, config.UdpStatPort)
	}
	if len(m.servers) < len(config.PusherEndpointsInfo.StatIps) {
		m.Stop()
		return false
	}
	return true
}

func (m *ServerManager) startOne(ip string, port int) {
	server := new(StatUdpServer)
	if !server.Start(ip, port) {
		logger.Logger.Error("[管控] udp 统计服务启动错误", zap.String("ip", ip), zap.Int("port", port))
		return
	}
	m.servers = append(m.servers, server)
	logger.Logger.Info("[管控] udp 统计服务启动成功", zap.String("ip", ip), zap.Int("port", port))
}

func (m *ServerManager) Stop() {
	for _, server := range m.servers {
		server.Stop()
	}
}

func (m *ServerManager) RunerCount() int {
	return len(m.servers)
}

type StatUdpServer struct {
	conn *net.UDPConn
}

func (s *StatUdpServer) Start(ip string, port int) bool {
	addr, err := net.ResolveUDPAddr("udp", fmt.Sprintf("%s:%d", ip, port))
	if err != nil {
		logger.Logger.Error("[管控] udp 统计服务端口错误", zap.String("ip", ip), zap.Int("port", port), zap.Error(err))
		return false
	}
	s.conn, err = net.ListenUDP("udp", addr)
	if err != nil {
		logger.Logger.Error("[管控] udp 统计服务监听错误", zap.String("ip", ip), zap.Int("port", port), zap.Error(err))
		return false
	}
	if err = s.conn.SetReadBuffer(config.UdpReceiveBuffSize); err != nil { // 设置接收缓冲区大小
		logger.Logger.Error("[管控] udp 统计服务设置缓冲区错误",
			zap.String("ip", ip), zap.Int("port", port), zap.Int("receiveBuffSize", config.UdpReceiveBuffSize), zap.Error(err))
		return false
	}
	go s.handleReceive()
	return true
}

func (s *StatUdpServer) Stop() {
	if s.conn != nil {
		_ = s.conn.Close()
	}
}

func (s *StatUdpServer) handleReceive() {
	defer s.Stop()
	var (
		v6        int
		goal      string
		uid       string
		bandwidth int64
	)
	buf := make([]byte, config.UdpReadBufferSize)
	for {
		n, addr, err := s.conn.ReadFromUDP(buf)
		if err != nil {
			continue
		}
		data := strings.Split(string(buf[:n]), ":")
		if len(data) < 4 {
			logger.Logger.Info("[统计] 数据错误", zap.String("ip", addr.IP.String()), zap.Strings("data", data))
			continue
		}
		v6, _ = strconv.Atoi(data[0])
		goal = data[1]
		uid = data[2]
		bandwidth, _ = strconv.ParseInt(data[3], 10, 64)
		go s.statData(v6, uid, bandwidth)
		logger.Logger.Info("[统计] 数据",
			zap.String("ip", addr.IP.String()), zap.String("goal", goal), zap.String("uid", uid), zap.Int64("bandwidth", bandwidth))
	}
}

func (s *StatUdpServer) statData(v6 int, uid string, bandwidth int64) {
	if v6 == 0 {
		if !service.SessionsInstance().ExistV4Session(uid) {
			service.SessionsInstance().AddV4Session(uid, bandwidth)
		} else {
			service.SessionsInstance().UpdateV4Session(uid)
		}
	} else {
		if !service.SessionsInstance().ExistV6Session(uid) {
			service.SessionsInstance().AddV6Session(uid, bandwidth)
		} else {
			service.SessionsInstance().UpdateV6Session(uid)
		}
	}
}
